#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

#include <mysql/mysql.h>

// MySQL连接配置
#define DB_HOST "localhost"
#define DB_USER "root"
#define DB_PASS "123456"
#define DB_NAME "snmp_data"
#define DB_PORT 3306

MYSQL *conn;

struct host {                            /* a list of hosts to query */
  const char *name;
  const char *community;
} hosts[] = {
  { "10.1.1.5",	"public" },
  { "10.1.1.6",	"public" },
  { "10.1.1.9",	"public" },
  { "10.1.1.10", "public" },
  { NULL }
};

struct oid {
  const char *Name;
  oid Oid[MAX_OID_LEN];
  int OidLen;
} oids[] = {
  { "1.3.6.1.2.1.1.5.0" },  // system.sysName.0
  { "1.3.6.1.2.1.2.2.1.10.9" }, // ifInOctets
  { "1.3.6.1.2.1.2.2.1.11.9" },  // ifInUcastPkts
  { "1.3.6.1.2.1.2.2.1.12.9" },  // ifInNUcastPkts
  { "1.3.6.1.2.1.2.2.1.14.9" },  // ifInErrors
  { "1.3.6.1.2.1.2.2.1.16.9" },  // ifOutOctets
  { "1.3.6.1.2.1.2.2.1.17.9" },  // ifOutUcastPkts
  { "1.3.6.1.2.1.2.2.1.18.9" },  // ifOutNUcastPkts
  { "1.3.6.1.2.1.2.2.1.20.9" },  // ifOutErrors
  { NULL }
};

// -------------------------------void initialize(void):处理struct oid中的Oid[MAC_OID_LEN]与OidLen-------------------------------
void initialize (void)
{
  struct oid *op = oids;    
  init_snmp("asynchapp");         /* initialize library */
  
   // 加载系统 MIB 路径
   add_mibdir("/usr/share/snmp/mibs");
    
   // 强制加载所有 MIB 文件
   netsnmp_init_mib();
   read_mib("/usr/share/snmp/mibs/SNMPv2-MIB.txt");  // 加载单个 MIB 文件

  while (op->Name) {               /* parse the oids */
    op->OidLen = sizeof(op->Oid)/sizeof(op->Oid[0]);
    if (!read_objid(op->Name, op->Oid, &op->OidLen)) {
      snmp_perror("read_objid");
      exit(1);
    }
    op++;
  }
}

// ************************************** poll all hosts in parallel */****************************************************
struct session {
  struct snmp_session *sess;		/* SNMP session data */
  struct oid *current_oid;		    /* How far in our poll are we */
} sessions[sizeof(hosts)/sizeof(hosts[0])];
       
int active_hosts;			         /* hosts that we have not completed */
  
int asynch_response(int operation, struct snmp_session *sp, int reqid, struct snmp_pdu *pdu, void *magic)    /* response handler */
{
  struct session *host = (struct session *)magic;
  struct snmp_pdu *req;

  if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
    if (print_result(STAT_SUCCESS, host->sess, pdu)) {
      host->current_oid++;			/* send next GET (if any) */
      if (host->current_oid->Name) {
	req = snmp_pdu_create(SNMP_MSG_GET);
	snmp_add_null_var(req, host->current_oid->Oid, host->current_oid->OidLen);
	if (snmp_send(host->sess, req))
	  return 1;
	else {
	  snmp_perror("snmp_send");
	  snmp_free_pdu(req);
	}
      }
    }
  }
  else
    print_result(STAT_TIMEOUT, host->sess, pdu);  
  active_hosts--;                            /* something went wrong (or end of variables) * this host not active any more */
    return 1;
}

// ---------------------------------------------------------------------void asynchronous(void)-------------------------------------------------------------------------------
void asynchronous(void)
{
  struct session *hs;
  struct host *hp;  

   //给每台主机发送oids[]中的第一个对象的请求，for循环发送，尔后每台主机返回响应后，再oids++，再向该主机发送下一个对象
    //请求数据报（肯定是在回调函数中完成的）
 for (hs = sessions, hp = hosts; hp->name; hs++, hp++) {                 /* startup all hosts */
    struct snmp_pdu *req;
    struct snmp_session sess;
    snmp_sess_init(&sess);			         /* initialize session */
    sess.version = SNMP_VERSION_2c;
    sess.peername = strdup(hp->name);
    sess.community = strdup(hp->community);
    sess.community_len = strlen(sess.community);
    sess.callback = asynch_response;		/* default callback */
    sess.callback_magic = hs;
    if (!(hs->sess = snmp_open(&sess))) {
      snmp_perror("snmp_open");
      continue;
    }
    hs->current_oid = oids;
    req = snmp_pdu_create(SNMP_MSG_GET);	/* send the first GET */
    snmp_add_null_var(req, hs->current_oid->Oid, hs->current_oid->OidLen);
    if (snmp_send(hs->sess, req))
      active_hosts++;
    else {
      snmp_perror("snmp_send");
      snmp_free_pdu(req);
    }
  }

  while (active_hosts) {           /* loop while any active hosts */
    int fds = 0, block = 1;
    fd_set fdset;
    struct timeval timeout;

    FD_ZERO(&fdset);
    snmp_select_info(&fds, &fdset, &timeout, &block);
    fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
    if (fds < 0) {
        perror("select failed");
        exit(1);
    }
    if (fds)
        snmp_read(&fdset);
    else
        snmp_timeout();
  }
  
  for (hp = hosts, hs = sessions; hp->name; hs++, hp++) {   /* cleanup */
    if (hs->sess) snmp_close(hs->sess);
  }
}

int connect_to_mysql() {
  conn = mysql_init(NULL);
  if (!mysql_real_connect(conn, DB_HOST, DB_USER, DB_PASS, 
                        DB_NAME, DB_PORT, NULL, 0)) {
      fprintf(stderr, "MySQL连接错误: %s\n", mysql_error(conn));
      return 0;
  }
  printf("成功连接到MySQL数据库\n");
  return 1;
}

int print_result(int status, struct snmp_session *sp, struct snmp_pdu *pdu) {
  char buf[1024];
  struct variable_list *vp;
  int ix;
  char query[2048];
  char value[512];
  char oid_str[256];
  char timestamp[64];
  struct timeval now;
  struct timezone tz;
  struct tm *tm;

  gettimeofday(&now, &tz);
  tm = localtime(&now.tv_sec);
  snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d",
           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
           tm->tm_hour, tm->tm_min, tm->tm_sec);

  switch (status) {
  case STAT_SUCCESS:
      vp = pdu->variables;
      if (pdu->errstat == SNMP_ERR_NOERROR) {
          while (vp) {
              snprint_variable(buf, sizeof(buf), vp->name, vp->name_length, vp);
              fprintf(stdout, "%s: %s\n", sp->peername, buf);

              // 提取OID和值
              snprint_objid(oid_str, sizeof(oid_str), vp->name, vp->name_length);
              snprint_value(value, sizeof(value), vp->name, vp->name_length, vp);

              // 构建并执行SQL插入语句
              snprintf(query, sizeof(query),
                      "INSERT INTO snmp_results "
                      "(device_ip, oid, value, timestamp) "
                      "VALUES ('%s', '%s', '%s', '%s')",
                      sp->peername, oid_str, value, timestamp);

              if (mysql_query(conn, query)) {
                  fprintf(stderr, "MySQL插入失败: %s\n", mysql_error(conn));
              }

              vp = vp->next_variable;
          }
      }
      else {
          // 错误处理（保持不变）
          for (ix = 1; vp && ix != pdu->errindex; vp = vp->next_variable, ix++);
          if (vp) snprint_objid(buf, sizeof(buf), vp->name, vp->name_length);
          else strcpy(buf, "(none)");
          fprintf(stdout, "%s: %s: %s\n",
                 sp->peername, buf, snmp_errstring(pdu->errstat));
      }
      return 1;
  case STAT_TIMEOUT:
      fprintf(stdout, "%s: Timeout\n", sp->peername);
      return 0;
  case STAT_ERROR:
      snmp_perror(sp->peername);
      return 0;
  }
  return 0;
}

// /**************************************/
int main (int argc, char **argv)
{
  initialize();
   // 初始化MySQL连接
   if (!connect_to_mysql()) {
      return 1;
  }
  printf("---------- asynchronous -----------\n");
  asynchronous();
  // 关闭MySQL连接
    mysql_close(conn);
  return 0;
}
